package com.zgg.core.utils

import com.zgg.core.annotation.HttpHandler
import java.io.File
import java.lang.reflect.Method
import java.net.URL
import java.util.*
import kotlin.reflect.KClass
import kotlin.reflect.KType


/**
 * @author: zgg
 * @date: 2021-07-03 21:43
 */
class Reflection {
    companion object {
        private val primitiveType = HashSet<KClass<*>>()

        init {
            primitiveType.add(Boolean::class)
            primitiveType.add(Byte::class)
            primitiveType.add(Int::class)
            primitiveType.add(Short::class)
            primitiveType.add(Double::class)
            primitiveType.add(Float::class)
            primitiveType.add(Long::class)
            primitiveType.add(String::class)
        }

        @Throws(Exception::class)
        fun findHandlerClass(pkg: String): Set<Class<*>> {
            val pkgPath = pkg.replace(".", "/")
            val resource: URL? = Reflection::class.java.classLoader.getResource(pkgPath)
            val classSet: MutableSet<Class<*>> = HashSet()
            if (resource == null) {
                return classSet
            }
            val file = File(resource.getFile())
            if (!file.exists()) {
                return classSet
            }
            val files = file.listFiles { pathname: File ->
                pathname.isDirectory || pathname.name.endsWith(".class")
            }
            if (files == null || files.size == 0) {
                return classSet
            }
            for (f in files) {
                if (f.isDirectory) {
                    val subDirClass = findHandlerClass(pkg + "." + f.name)
                    if (subDirClass.size != 0) {
                        classSet.addAll(subDirClass)
                    }
                } else {
                    val className = f.name.replace(".class", "")
                    val clazz: Class<*>? = Class.forName("$pkg.$className")
                    clazz?.let {
                        val declaredMethods: Array<Method> = clazz.declaredMethods
                        for (method in declaredMethods) {
                            val annotation: HttpHandler? = method.getAnnotation(HttpHandler::class.java)
                            if (annotation != null) {
                                classSet.add(clazz)
                                break
                            }
                        }
                    }
                }
            }
            return classSet
        }

        @Throws(Exception::class)
        fun findHandlerKClass(pkg: String): Set<KClass<*>> {
            val pkgPath = pkg.replace(".", "/")
            val resource: URL? = Reflection::class.java.classLoader.getResource(pkgPath)
            val classSet: MutableSet<KClass<*>> = HashSet()
            if (resource == null) {
                return classSet
            }
            val file = File(resource.file)
            if (!file.exists()) {
                return classSet
            }
            val files = file.listFiles { pathname: File ->
                pathname.isDirectory || pathname.name.endsWith(".class")
            }
            if (files == null || files.size == 0) {
                return classSet
            }
            for (f in files) {
                if (f.isDirectory) {
                    val subDirClass = findHandlerKClass(pkg + "." + f.name)
                    if (subDirClass.size != 0) {
                        classSet.addAll(subDirClass)
                    }
                } else {
                    //扫描类是否有HttpHandler 注解
                    val className = f.name.replace(".class", "")
                    val clazz: Class<*>? = Class.forName("$pkg.$className")
                    clazz?.let {
                        val declaredMethods: Array<Method> = clazz.declaredMethods
                        for (method in declaredMethods) {
                            val annotation: HttpHandler? = method.getAnnotation(HttpHandler::class.java)
                            if (annotation != null) {
                                classSet.add(clazz.kotlin)
                                break
                            }
                        }
                    }
                }
            }
            return classSet
        }

        fun isPrimitiveType(type: KType): Boolean {
            return primitiveType.contains(type.classifier)
        }

    }

}

fun main(agrs: Array<String>) {
    val handlerClass: Set<Class<*>> = Reflection.findHandlerClass("pers.lcnap.vertxwebframework.test")
}